﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using TtfLibrary.CommonStructures;

namespace TtfLibrary
{
    public static class TtfUtilities
    {
        public static void FixFileForWPF(TtfFile file)
        {
            if (!file.Name.NameRecord.Any(rec => rec.NameId == 2))
                file.Name.NameRecord = file.Name.NameRecord.Union(new[] { new TtfNameRecord()
                {
                    PlatformId = 1,
                    EncodingId = 0,
                    LanguageId = 0,
                    NameId = 2,
                    Value = "Regular"
                } }).ToArray();

            if (!file.Name.NameRecord.Any(rec => rec.NameId == 1))
                file.Name.NameRecord = file.Name.NameRecord.Union(new[]
                {
                    new TtfNameRecord()
                    {
                        PlatformId = 1,
                        EncodingId = 0,
                        LanguageId = 0,
                        NameId = 1,
                        Value = file.Name.NameRecord.Where(rec => rec.NameId == 6).Select(rec => rec.Value).FirstOrDefault()
                } }).ToArray();            
        }

        public static void FixFileForWindows(TtfFile file)
        {
            FixFileForWPF(file);

            file.Maxp.MaxPoints = (ushort)file.Glyf.Glyphs.Where(g => g.SimpleGlyph != null).Select(g => g.SimpleGlyph.CoordinateCount).Max();
            file.Maxp.MaxContours = (ushort)file.Glyf.Glyphs.Where(g => g.SimpleGlyph != null).Select(g => g.SimpleGlyph.NumberOfContours).Max();
            file.Maxp.MaxCompositeContours = 0;
            file.Maxp.MaxCompositePoints = 0;
            file.Maxp.MaxComponentDepth = 0;
            file.Maxp.MaxComponentElements = 0;

            file.Head.XMin = file.Glyf.Glyphs.Min(g => g.XMin);
            file.Head.YMin = file.Glyf.Glyphs.Min(g => g.YMin);
            file.Head.XMax = file.Glyf.Glyphs.Max(g => g.XMax);
            file.Head.YMax = file.Glyf.Glyphs.Max(g => g.YMax);

            file.Hhea.MinLeftSideBearing = file.Hmtx.HMetrics.Select(hm => hm.Lsb).Min();
            file.Hhea.AdvanceWidthMax = file.Hmtx.HMetrics.Select(hm => hm.AdvanceWidth).Max();

            var l = file.Glyf.Glyphs.Length;
            var rsb = new int[l];
            var extent = new int[l];
            for (int i = 0; i < l; i++)
            {
                var xMax = file.Glyf.Glyphs[i].XMax;
                var xMin = file.Glyf.Glyphs[i].XMin;
                var lsb = file.Hmtx.HMetrics[i].Lsb;
                var aw = file.Hmtx.HMetrics[i].AdvanceWidth;

                rsb[i] = aw - (lsb + xMax - xMin);
                extent[i] = lsb + xMax - xMin;
            }

            file.Hhea.MinRightSideBearing = (short)rsb.Min();
            file.Hhea.XMaxExtent = (short)extent.Max();

            //file.Tables["name"] = file.Name = fileGood.Name;
            //var copyNameRec = new[] { 0,1 };
            //file.Name.NameRecord = fileGood.Name.NameRecord.Where((rec, idx) => copyNameRec.Contains(idx)).ToArray();

            /*file.Tables["OS/2"] = file.OS2 = fileGood.OS2;
            file.OS2.UlUnicodeRange1 = 0;
            file.OS2.UlUnicodeRange2 = 0;
            file.OS2.UlUnicodeRange3 = 0;
            file.OS2.UlUnicodeRange4 = 0;*/

            //fileGood.TableOrders = file.TableOrders;

            file.Maxp.MaxSizeOfInstructions = file.Glyf.Glyphs.Select(g => g.SimpleGlyph).Where(g => g != null).Select(g => g.InstructionLength).Max();
            file.Head.FontRevision = new TtfFixed() { Major = 1, Minor = 0 };

            foreach(var rec in file.Cmap.EncodingRecords.Where(rec => rec.Table.Format == 6))
            {
                var f6 = rec.Table.Format6;
                var f0 = new TtfFormat0Encoding();

                f0.Length = 262;
                for(int i = 0; i < f6.EntryCount; i++)
                    f0.GlyphIdArray[f6.FirstCode + i] = (byte)f6.GlyphIdArray[i];

                rec.Table.Format0 = f0;
                rec.Table.Format = 0;
            }

            /*file.Tables["cmap"] = file.Cmap = fileGood.Cmap;
            file.Cmap.EncodingRecords = new[] { file.Cmap.EncodingRecords[1] };*/
        }

        public static string[] CompareOriginalRewrite(TtfFile ttfFile, string outputPath = null)
        {
            var changedTables = new List<string>();

            foreach (var tableName in ttfFile.Tables.Keys)
            {
                var tableNameSafe = tableName.Replace("/", "");

                var msRewrite = new MemoryStream();
                new StructureWriter() { Stream = msRewrite }.WriteObject(ttfFile.Tables[tableName]);

                var originalContent = ttfFile.TableContents[tableName];
                var rewriteContent = msRewrite.ToArray();

                if (!originalContent.SequenceEqual(rewriteContent))
                    changedTables.Add(tableName);

                if (outputPath != null)
                {
                    File.WriteAllBytes(String.Format(@"{1}\table_{0}_original.ttf", tableNameSafe, outputPath), originalContent);
                    File.WriteAllBytes(String.Format(@"{1}\table_{0}_rewrite.ttf", tableNameSafe, outputPath), rewriteContent);
                }
            }

            return changedTables.ToArray();
        }
    }
}
